//BNB balancer, Random & PRandom
//$Id: bnb_balancer_random.h 709 2012-05-28 15:13:33Z Oleg.Bulychov@gmail.com $
#pragma once

//__________________________________________________________________________________
#include "src/heo/include/random.h"
//__________________________________________________________________________________
template<class Recv, class IBSend>
class bnb_balancer
{
protected:
    int cooperation_rate_;
    //bool async_mode_;
    int type_;//0 - ub only, 1 - Random, 2 - PRandom
public:
    bnb_balancer()
    {
        accept(meta::set_default_values());
    }

    static char const* get_Name() { return "coop"; }
    static char const* get_Section() { return get_Name(); }

    template<class V>
    void accept(V& v)
    {
        //v(VAR_(async_mode),                 false);
        v(VAR_(cooperation_rate),           25);
        v(VAR_(type),                       0);
    }

    //bool is_Async_Mode() const
    //{
    //    return async_mode_;
    //}

    int get_Rate() const
    {
        return cooperation_rate_;
    }

    template<class S, class Comm, class BNB_Data>
    void balance_Sync(S& solver, int rank, int np, int step,
        Comm& comm, BNB_Data* pData)
    {
        if (!type_)
            return;
        size_t pq_size = solver.pq_.size();

        //:Random  id = pq_size - 1;
        //:PRandom id = pq_size - 2;

        size_t id = pq_size - type_;

        int dst = pData[rank].dst_;
        ref_ptr<typename S::TTask> task;
        IBSend out(dst, comm);
        int count = 0;
        if (dst != rank && id < pq_size)
            ++count;
        out << count;
        if (count != 0)
        {
            task = solver.pq_[id];
            solver.pq_.erase(id);

            out << *task;
            ++solver.stat_.sent_;
        }
        //std::cout << "sent: " << rank << " => " << dst << std::endl;
        for (int i = 0; i < np; ++i)
        {
            if (i == rank)
                continue;
            if (pData[i].dst_ != rank)
                continue;
            Recv in(i, comm);
            int count;
            in >> count;
            //std::cout << "recv: " << rank << " <= " << i << std::endl;
            for (int j = 0; j < count; ++j)
            {
                solver.recv_Task(in);
                ++solver.stat_.received_;
            }
        }
        comm.barrier();
        pData[rank].dst_ = solver.get_Rnd().next_UInt(np);
    }
};
//__________________________________________________________________________________

//EOF!
